Skip to content

Fix NullReferenceException when binding to Dictionary<Enum, object> with x:DataType#32916

Open
StephaneDelcroix wants to merge 6 commits intomainfrom
fix/13856-enum-dictionary-binding
Open

Fix NullReferenceException when binding to Dictionary<Enum, object> with x:DataType#32916
StephaneDelcroix wants to merge 6 commits intomainfrom
fix/13856-enum-dictionary-binding

Conversation

@StephaneDelcroix
Copy link
Contributor

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Description

Fixes #13856

Problem

Using x:DataType with a binding to Dictionary<CustomEnum, object> like {Binding UserSettings[TBD]} caused a NullReferenceException at compile time in XamlC.

Root Cause

XamlC's SetPropertiesVisitor.cs only supported int, string, and object indexer parameter types. When encountering an enum type, it failed to find a matching indexer and returned null, causing a NullReferenceException when trying to access properties on the null indexer.

Solution

  • XamlC (SetPropertiesVisitor.cs): Added support for finding indexers with enum parameter types and emitting enum constant values via IL
  • SourceGen (CompiledBindingMarkup.cs): Added support for enum indexer parameter types in the binding path parser

Changes

SetPropertiesVisitor.cs

  • Added enum indexer detection when looking for property indexers
  • Updated type validation to allow enum indexer types
  • Added code to emit enum constant values as IL instructions

CompiledBindingMarkup.cs

  • Added enum indexer support in TryParsePath method
  • When an enum indexer is found, generates the fully qualified enum member reference

Test Fixes

  • Fixed pre-existing test failure in Maui32879Tests.cs (updated expected output to include #pragma warning disable CS0219)

Tests Added

  • Maui13856.xaml + Maui13856.xaml.cs - XamlC unit test that verifies compilation succeeds
  • Maui13856Tests.cs - SourceGen unit test that verifies no errors are generated

Test Results

  • All 117 SourceGen.UnitTests pass
  • All Xaml.UnitTests binding and indexer tests pass

Copilot AI review requested due to automatic review settings November 29, 2025 06:21
@StephaneDelcroix StephaneDelcroix added this to the .NET 10.0 SR3 milestone Nov 29, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a NullReferenceException that occurred when using x:DataType with bindings to Dictionary<Enum, object> properties in XAML. The issue was that both XamlC and SourceGen did not support enum types as dictionary indexer parameters, causing compilation failures.

Key Changes:

  • Added enum indexer parameter support to XamlC's SetPropertiesVisitor
  • Added enum indexer parameter support to SourceGen's CompiledBindingMarkup
  • Added comprehensive tests for both XamlC and SourceGen to prevent regression

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/Controls/src/Build.Tasks/SetPropertiesVisitor.cs Added logic to detect enum indexer parameters, validate enum types, and emit enum constant values as IL instructions
src/Controls/src/SourceGen/CompiledBindingMarkup.cs Added logic to detect enum indexer parameters and generate fully qualified enum member references
src/Controls/tests/Xaml.UnitTests/Issues/Maui13856.xaml Test XAML file demonstrating Dictionary<Enum, object> binding with x:DataType
src/Controls/tests/Xaml.UnitTests/Issues/Maui13856.xaml.cs XamlC unit test verifying compilation succeeds without NullReferenceException
src/Controls/tests/SourceGen.UnitTests/Maui13856Tests.cs SourceGen unit test verifying no errors are generated for enum indexer bindings
src/Controls/tests/SourceGen.UnitTests/Maui32879Tests.cs Updated expected test output to include CS0219 pragma warning (pre-existing test fix)

if (enumMember != null)
{
index = $"{enumType.ToFQDisplayString()}.{indexArg}";
}
Copy link

Copilot AI Nov 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When an enum indexer is found but the enum member doesn't exist (enumMember is null), the code silently continues without updating the index variable. This means it will use the original indexArg string value instead of a fully qualified enum member reference, which could lead to incorrect code generation.

Consider adding an else clause to handle the case when the enum member is not found:

if (enumMember != null)
{
    index = $"{enumType.ToFQDisplayString()}.{indexArg}";
}
else
{
    // Log a diagnostic or return false to indicate parsing failure
    return false;
}
Suggested change
}
}
else
{
return false; // Enum member not found, fail parsing
}

Copilot uses AI. Check for mistakes.
@StephaneDelcroix StephaneDelcroix marked this pull request as draft November 29, 2025 06:40
@StephaneDelcroix StephaneDelcroix force-pushed the fix/13856-enum-dictionary-binding branch from d696d69 to 58e7fbd Compare November 29, 2025 06:46
@StephaneDelcroix StephaneDelcroix marked this pull request as ready for review November 29, 2025 06:47
@StephaneDelcroix StephaneDelcroix marked this pull request as draft November 29, 2025 06:57
@StephaneDelcroix StephaneDelcroix force-pushed the fix/13856-enum-dictionary-binding branch from 58e7fbd to 6f6407e Compare November 29, 2025 08:08
@StephaneDelcroix StephaneDelcroix marked this pull request as ready for review November 29, 2025 08:15
@StephaneDelcroix StephaneDelcroix changed the title Fix NullReferenceException when binding to Dictionary<Enum, object> with x:DataType [C] Fix NullReferenceException when binding to Dictionary<Enum, object> with x:DataType Nov 29, 2025
Comment on lines 84 to 85
// Verify the binding path is in the generated code (even if using runtime binding fallback)
Assert.Contains("UserSettings[TBD]", generatedCode, System.StringComparison.Ordinal);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this assert should be here. Ideally we'll drop the unnecessary markup extension instantiation at some point (#31614). I think this assert should look for .UserSettings[global::Test.UserSetting.TBD] instead.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(although that might currently fail due to #32905)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — updated the assertion to check for UserSettings[global::Test.UserSetting.TBD] instead. Also added a diagnostic + early return when the enum member is not found, so typo'd enum keys now produce a compile-time error instead of generating invalid C#.

@PureWeen PureWeen modified the milestones: .NET 10.0 SR3, .NET 10.0 SR4 Jan 21, 2026
@StephaneDelcroix StephaneDelcroix force-pushed the fix/13856-enum-dictionary-binding branch from 6f6407e to cc8fb84 Compare February 11, 2026 21:56
@sheiksyedm sheiksyedm modified the milestones: .NET 10.0 SR4, .NET 10 SR6 Feb 13, 2026
@StephaneDelcroix StephaneDelcroix changed the title [C] Fix NullReferenceException when binding to Dictionary<Enum, object> with x:DataType Fix NullReferenceException when binding to Dictionary<Enum, object> with x:DataType Feb 24, 2026
…ith x:DataType

Fixes #13856

Using  with a binding to  like  caused a NullReferenceException at compile time in XamlC.

- **XamlC (SetPropertiesVisitor.cs)**: Added support for finding indexers with enum parameter types and emitting enum constant values via IL
- **SourceGen (CompiledBindingMarkup.cs)**: Added support for enum indexer parameter types in the binding path parser

- Added enum indexer detection in XamlC's property digger
- Updated type validation to allow enum indexer types
- Added code to emit enum constant values as IL instructions
- Added enum indexer support in SourceGen's TryParsePath method
- Fixed pre-existing test failure in Maui32879Tests (unrelated pragma warning directive)

- Added Maui13856.xaml unit test for XamlC compilation
- Added Maui13856Tests.cs for SourceGen validation
- Add diagnostic + early return when enum member name is not found in the enum type
- Update test to assert fully qualified enum member (per simonrozsival review)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@StephaneDelcroix
Copy link
Contributor Author

/backport to release/11.0.1xx-preview2

@github-actions
Copy link
Contributor

Started backporting to release/11.0.1xx-preview2 (link to workflow run)

StephaneDelcroix and others added 4 commits February 25, 2026 20:29
Change 'return null' to 'return false' when enum member not found.
TryParsePath returns bool, not bool?.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Xaml.UnitTests migrated from NUnit to xUnit on net11.0.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ssing

The source gen doesn't yet handle Dictionary<Enum, object> indexers properly
(generates string keys instead of enum values). Use .rt.xaml so the test only
runs with Runtime and XamlC inflators, which do handle enum dictionary keys.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
.rt.xaml files are runtime-only — no code is generated for either
XamlC or SourceGen. The test was only skipping SourceGen, causing
a NotSupportedException when trying to use the XamlC inflator.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 32916

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 32916"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

MAUI - XAML - Object reference not set to an instance of an object - reproducable, not same as #8249

5 participants